home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / util / dgn_comp.y < prev    next >
Text File  |  1993-01-18  |  16KB  |  684 lines

  1. %{
  2. /*    SCCS Id: @(#)dgn_comp.c    3.1    93/01/17    */
  3. /*    Copyright (c) 1989 by Jean-Christophe Collet */
  4. /*    Copyright (c) 1990 by M. Stephenson                  */
  5. /* NetHack may be freely redistributed.  See license for details. */
  6.  
  7. /*
  8.  * This file contains the Dungeon Compiler code
  9.  */
  10.  
  11. /* In case we're using bison in AIX.  This definition must be
  12.  * placed before any other C-language construct in the file
  13.  * excluding comments and preprocessor directives (thanks IBM
  14.  * for this wonderful feature...).
  15.  *
  16.  * Note: some cpps barf on this 'undefined control' (#pragma).
  17.  * Addition of the leading space seems to prevent barfage for now,
  18.  * and AIX will still see the directive in its non-standard locale.
  19.  */
  20.  
  21. #ifdef _AIX
  22.  #pragma alloca        /* keep leading space! */
  23. #endif
  24.  
  25. #include "config.h"
  26. #include "dgn_file.h"
  27.  
  28. void FDECL(yyerror, (char *));
  29. void FDECL(yywarning, (char *));
  30. int NDECL(yylex);
  31. int NDECL(yyparse);
  32. int FDECL(getchain, (char *));
  33. int NDECL(check_dungeon);
  34. int NDECL(check_branch);
  35. int NDECL(check_level);
  36. void NDECL(init_dungeon);
  37. void NDECL(init_branch);
  38. void NDECL(init_level);
  39. void NDECL(output_dgn);
  40.  
  41. #ifdef AMIGA
  42. # undef    printf
  43. #ifndef    LATTICE
  44. # define    memset(addr,val,len)    setmem(addr,len,val)
  45. #endif
  46. #endif
  47.  
  48. #ifdef MICRO
  49. # undef exit
  50. extern void FDECL(exit, (int));
  51. #endif
  52.  
  53. #undef NULL
  54.  
  55. #define ERR        (-1)
  56.  
  57. static struct couple couple;
  58. static struct tmpdungeon tmpdungeon[MAXDUNGEON];
  59. static struct tmplevel tmplevel[LEV_LIMIT];
  60. static struct tmpbranch tmpbranch[BRANCH_LIMIT];
  61.  
  62. static int in_dungeon = 0, n_dgns = -1, n_levs = -1, n_brs = -1;
  63.  
  64. extern int fatal_error;
  65. extern char* fname;
  66.  
  67. %}
  68.  
  69. %union
  70. {
  71.     int    i;
  72.     char*    str;
  73. }
  74.  
  75. %token    <i>    INTEGER
  76. %token    <i>    A_DUNGEON BRANCH CHBRANCH LEVEL RNDLEVEL CHLEVEL RNDCHLEVEL
  77. %token    <i>    UP_OR_DOWN PROTOFILE DESCRIPTION DESCRIPTOR LEVELDESC
  78. %token    <i>    ALIGNMENT LEVALIGN ENTRY STAIR NO_UP NO_DOWN PORTAL
  79. %token    <str>    STRING
  80. %type   <i>    optional_int direction branch_type
  81. %start    file
  82.  
  83. %%
  84. file        : /* nothing */
  85.         | dungeons
  86.           {
  87.             output_dgn();
  88.           }
  89.         ;
  90.  
  91. dungeons    : dungeon
  92.         | dungeons dungeon
  93.         ;
  94.  
  95. dungeon        : dungeonline
  96.         | dungeondesc
  97.         | branches
  98.         | levels
  99.         ;
  100.  
  101. dungeonline    : A_DUNGEON ':' STRING STRING rcouple optional_int
  102.           {
  103.             init_dungeon();
  104.             strcpy(tmpdungeon[n_dgns].name, $3);
  105.             if (!strcmp($4, "none"))
  106.                 tmpdungeon[n_levs].boneschar = '\0';
  107.             else if ($4[1])
  108.                 yyerror("Bones marker must be a single char, or \"none\"!");
  109.             else
  110.                 tmpdungeon[n_dgns].boneschar = $4[0];
  111.             tmpdungeon[n_dgns].lev.base = couple.base;
  112.             tmpdungeon[n_dgns].lev.rand = couple.rand;
  113.             tmpdungeon[n_dgns].chance = $6;
  114.           }
  115.         ;
  116.  
  117. optional_int    : /* nothing */
  118.           {
  119.             $$ = 0;
  120.           }
  121.         | INTEGER
  122.           {
  123.             $$ = $1;
  124.           }
  125.         ;
  126.  
  127. dungeondesc    : entry
  128.         | descriptions
  129.         | prototype
  130.         ;
  131.  
  132. entry        : ENTRY ':' INTEGER
  133.           {
  134.             tmpdungeon[n_dgns].entry_lev = $3;
  135.           }
  136.         ;
  137.  
  138. descriptions    : desc
  139.         ;
  140.  
  141. desc        : DESCRIPTION ':' DESCRIPTOR
  142.           {
  143.             if($<i>3 <= TOWN || $<i>3 >= D_ALIGN_CHAOTIC)
  144.                 yyerror("Illegal description - ignoring!");
  145.             else
  146.                 tmpdungeon[n_dgns].flags |= $<i>3 ;
  147.           }
  148.         | ALIGNMENT ':' DESCRIPTOR
  149.           {
  150.             if($<i>3 && $<i>3 < D_ALIGN_CHAOTIC)
  151.                 yyerror("Illegal alignment - ignoring!");
  152.             else
  153.                 tmpdungeon[n_dgns].flags |= $<i>3 ;
  154.           }
  155.         ;
  156.  
  157. prototype    : PROTOFILE ':' STRING
  158.           {
  159.             strcpy(tmpdungeon[n_dgns].protoname, $3);
  160.           }
  161.         ;
  162.  
  163. levels        : level1
  164.         | level2
  165.         | levdesc
  166.         | chlevel1
  167.         | chlevel2
  168.         ;
  169.  
  170. level1        : LEVEL ':' STRING STRING '@' acouple
  171.           {
  172.             init_level();
  173.             strcpy(tmplevel[n_levs].name, $3);
  174.             if (!strcmp($4, "none"))
  175.                 tmplevel[n_levs].boneschar = '\0';
  176.             else if ($4[1])
  177.                 yyerror("Bones marker must be a single char, or \"none\"!");
  178.             else
  179.                 tmplevel[n_levs].boneschar = $4[0];
  180.             tmplevel[n_levs].lev.base = couple.base;
  181.             tmplevel[n_levs].lev.rand = couple.rand;
  182.             tmpdungeon[n_dgns].levels++;
  183.           }
  184.         | RNDLEVEL ':' STRING STRING '@' acouple INTEGER
  185.           {
  186.             init_level();
  187.             strcpy(tmplevel[n_levs].name, $3);
  188.             if (!strcmp($4, "none"))
  189.                 tmplevel[n_levs].boneschar = '\0';
  190.             else if ($4[1])
  191.                 yyerror("Bones marker must be a single char, or \"none\"!");
  192.             else
  193.                 tmplevel[n_levs].boneschar = $4[0];
  194.             tmplevel[n_levs].lev.base = couple.base;
  195.             tmplevel[n_levs].lev.rand = couple.rand;
  196.             tmplevel[n_levs].rndlevs = $7;
  197.             tmpdungeon[n_dgns].levels++;
  198.           }
  199.         ;
  200.  
  201. level2        : LEVEL ':' STRING STRING '@' acouple INTEGER
  202.           {
  203.             init_level();
  204.             strcpy(tmplevel[n_levs].name, $3);
  205.             if (!strcmp($4, "none"))
  206.                 tmplevel[n_levs].boneschar = '\0';
  207.             else if ($4[1])
  208.                 yyerror("Bones marker must be a single char, or \"none\"!");
  209.             else
  210.                 tmplevel[n_levs].boneschar = $4[0];
  211.             tmplevel[n_levs].lev.base = couple.base;
  212.             tmplevel[n_levs].lev.rand = couple.rand;
  213.             tmplevel[n_levs].chance = $7;
  214.             tmpdungeon[n_dgns].levels++;
  215.           }
  216.         | RNDLEVEL ':' STRING STRING '@' acouple INTEGER INTEGER
  217.           {
  218.             init_level();
  219.             strcpy(tmplevel[n_levs].name, $3);
  220.             if (!strcmp($4, "none"))
  221.                 tmplevel[n_levs].boneschar = '\0';
  222.             else if ($4[1])
  223.                 yyerror("Bones marker must be a single char, or \"none\"!");
  224.             else
  225.                 tmplevel[n_levs].boneschar = $4[0];
  226.             tmplevel[n_levs].lev.base = couple.base;
  227.             tmplevel[n_levs].lev.rand = couple.rand;
  228.             tmplevel[n_levs].chance = $7;
  229.             tmplevel[n_levs].rndlevs = $8;
  230.             tmpdungeon[n_dgns].levels++;
  231.           }
  232.         ;
  233.  
  234. levdesc        : LEVELDESC ':' DESCRIPTOR
  235.           {
  236.             if($<i>3 >= D_ALIGN_CHAOTIC)
  237.                 yyerror("Illegal description - ignoring!");
  238.             else
  239.                 tmplevel[n_levs].flags |= $<i>3 ;
  240.           }
  241.         | LEVALIGN ':' DESCRIPTOR
  242.           {
  243.             if($<i>3 && $<i>3 < D_ALIGN_CHAOTIC)
  244.                 yyerror("Illegal alignment - ignoring!");
  245.             else
  246.                 tmplevel[n_levs].flags |= $<i>3 ;
  247.           }
  248.         ;
  249.  
  250. chlevel1    : CHLEVEL ':' STRING STRING STRING '+' rcouple
  251.           {
  252.             init_level();
  253.             strcpy(tmplevel[n_levs].name, $3);
  254.             if (!strcmp($4, "none"))
  255.                 tmplevel[n_levs].boneschar = '\0';
  256.             else if ($4[1])
  257.                 yyerror("Bones marker must be a single char, or \"none\"!");
  258.             else
  259.                 tmplevel[n_levs].boneschar = $4[0];
  260.             tmplevel[n_levs].chain = getchain($5);
  261.             tmplevel[n_levs].lev.base = couple.base;
  262.             tmplevel[n_levs].lev.rand = couple.rand;
  263.             if(!check_level()) n_levs--;
  264.             else tmpdungeon[n_dgns].levels++;
  265.           }
  266.         | RNDCHLEVEL ':' STRING STRING STRING '+' rcouple INTEGER
  267.           {
  268.             init_level();
  269.             strcpy(tmplevel[n_levs].name, $3);
  270.             if (!strcmp($4, "none"))
  271.                 tmplevel[n_levs].boneschar = '\0';
  272.             else if ($4[1])
  273.                 yyerror("Bones marker must be a single char, or \"none\"!");
  274.             else
  275.                 tmplevel[n_levs].boneschar = $4[0];
  276.             tmplevel[n_levs].chain = getchain($5);
  277.             tmplevel[n_levs].lev.base = couple.base;
  278.             tmplevel[n_levs].lev.rand = couple.rand;
  279.             tmplevel[n_levs].rndlevs = $8;
  280.             if(!check_level()) n_levs--;
  281.             else tmpdungeon[n_dgns].levels++;
  282.           }
  283.         ;
  284.  
  285. chlevel2    : CHLEVEL ':' STRING STRING STRING '+' rcouple INTEGER
  286.           {
  287.             init_level();
  288.             strcpy(tmplevel[n_levs].name, $3);
  289.             if (!strcmp($4, "none"))
  290.                 tmplevel[n_levs].boneschar = '\0';
  291.             else if ($4[1])
  292.                 yyerror("Bones marker must be a single char, or \"none\"!");
  293.             else
  294.                 tmplevel[n_levs].boneschar = $4[0];
  295.             tmplevel[n_levs].chain = getchain($5);
  296.             tmplevel[n_levs].lev.base = couple.base;
  297.             tmplevel[n_levs].lev.rand = couple.rand;
  298.             tmplevel[n_levs].chance = $8;
  299.             if(!check_level()) n_levs--;
  300.             else tmpdungeon[n_dgns].levels++;
  301.           }
  302.         | RNDCHLEVEL ':' STRING STRING STRING '+' rcouple INTEGER INTEGER
  303.           {
  304.             init_level();
  305.             strcpy(tmplevel[n_levs].name, $3);
  306.             if (!strcmp($4, "none"))
  307.                 tmplevel[n_levs].boneschar = '\0';
  308.             else if ($4[1])
  309.                 yyerror("Bones marker must be a single char, or \"none\"!");
  310.             else
  311.                 tmplevel[n_levs].boneschar = $4[0];
  312.             tmplevel[n_levs].chain = getchain($5);
  313.             tmplevel[n_levs].lev.base = couple.base;
  314.             tmplevel[n_levs].lev.rand = couple.rand;
  315.             tmplevel[n_levs].chance = $8;
  316.             tmplevel[n_levs].rndlevs = $9;
  317.             if(!check_level()) n_levs--;
  318.             else tmpdungeon[n_dgns].levels++;
  319.           }
  320.         ;
  321.  
  322. branches    : branch
  323.         | chbranch
  324.         ;
  325.  
  326. branch        : BRANCH ':' STRING '@' acouple branch_type direction
  327.           {
  328.             init_branch();
  329.             strcpy(tmpbranch[n_brs].name, $3);
  330.             tmpbranch[n_brs].lev.base = couple.base;
  331.             tmpbranch[n_brs].lev.rand = couple.rand;
  332.             tmpbranch[n_brs].type = $6;
  333.             tmpbranch[n_brs].up = $7;
  334.             if(!check_branch()) n_brs--;
  335.             else tmpdungeon[n_dgns].branches++;
  336.           }
  337.         ;
  338.  
  339. chbranch    : CHBRANCH ':' STRING STRING '+' rcouple branch_type direction
  340.           {
  341.             init_branch();
  342.             strcpy(tmpbranch[n_brs].name, $3);
  343.             tmpbranch[n_brs].chain = getchain($4);
  344.             tmpbranch[n_brs].lev.base = couple.base;
  345.             tmpbranch[n_brs].lev.rand = couple.rand;
  346.             tmpbranch[n_brs].type = $7;
  347.             tmpbranch[n_brs].up = $8;
  348.             if(!check_branch()) n_brs--;
  349.             else tmpdungeon[n_dgns].branches++;
  350.           }
  351.         ;
  352.  
  353. branch_type    : /* nothing */
  354.           {
  355.             $$ = TBR_STAIR;    /* two way stair */
  356.           }
  357.         | STAIR
  358.           {
  359.             $$ = TBR_STAIR;    /* two way stair */
  360.           }
  361.         | NO_UP
  362.           {
  363.             $$ = TBR_NO_UP;    /* no up staircase */
  364.           }
  365.         | NO_DOWN
  366.           {
  367.             $$ = TBR_NO_DOWN;    /* no down staircase */
  368.           }
  369.         | PORTAL
  370.           {
  371.             $$ = TBR_PORTAL;    /* portal connection */
  372.           }
  373.         ;
  374.  
  375. direction    : /* nothing */
  376.           {
  377.             $$ = 0;    /* defaults to down */
  378.           }
  379.         | UP_OR_DOWN
  380.           {
  381.             $$ = $1;
  382.           }
  383.         ;
  384.  
  385. /*
  386.  *    acouple rules:
  387.  *
  388.  *    (base, range) where:
  389.  *
  390.  *        base is either a positive or negative integer with a value
  391.  *        less than or equal to MAXLEVEL.
  392.  *        base > 0 indicates the base level.
  393.  *        base < 0 indicates reverse index (-1 == lowest level)
  394.  *
  395.  *        range is the random component.
  396.  *        if range is zero, there is no random component.
  397.  *        if range is -1 the dungeon loader will randomize between
  398.  *        the base and the end of the dungeon.
  399.  *        during dungeon load, range is always *added* to the base,
  400.  *        therefore range + base(converted) must not exceed MAXLEVEL.
  401.  */
  402. acouple        : '(' INTEGER ',' INTEGER ')'
  403.           {
  404.             if ($2 < -MAXLEVEL || $2 > MAXLEVEL) {
  405.                 yyerror("Abs base out of dlevel range - zeroing!");
  406.                 couple.base = couple.rand = 0;
  407.             } else if ($4 < -1 ||
  408.                 (($2 < 0) ? (MAXLEVEL + $2 + $4 + 1) > MAXLEVEL :
  409.                     ($2 + $4) > MAXLEVEL)) {
  410.                 yyerror("Abs range out of dlevel range - zeroing!");
  411.                 couple.base = couple.rand = 0;
  412.             } else {
  413.                 couple.base = $2;
  414.                 couple.rand = $4;
  415.             }
  416.           }
  417.         ;
  418.  
  419. /*
  420.  *    rcouple rules:
  421.  *
  422.  *    (base, range) where:
  423.  *
  424.  *        base is either a positive or negative integer with a value
  425.  *        less than or equal to MAXLEVEL.
  426.  *        base > 0 indicates a forward index.
  427.  *        base < 0 indicates a reverse index.
  428.  *        base == 0 indicates on the parent level.
  429.  *
  430.  *        range is the random component.
  431.  *        if range is zero, there is no random component.
  432.  *        during dungeon load, range is always *added* to the base,
  433.  *        range + base(converted) may be very large.  The dungeon
  434.  *        loader will then correct to "between here and the top/bottom".
  435.  *
  436.  *        There is no practical way of specifying "between here and the
  437.  *        nth / nth last level".
  438.  */
  439. rcouple        : '(' INTEGER ',' INTEGER ')'
  440.           {
  441.             if ($2 < -MAXLEVEL || $2 > MAXLEVEL) {
  442.                 yyerror("Rel base out of dlevel range - zeroing!");
  443.                 couple.base = couple.rand = 0;
  444.             } else {
  445.                 couple.base = $2;
  446.                 couple.rand = $4;
  447.             }
  448.           }
  449.         ;
  450. %%
  451.  
  452. void
  453. init_dungeon()
  454. {
  455.     if(++n_dgns > MAXDUNGEON) {
  456.         fprintf(stderr, "FATAL - Too many dungeons (limit: %d).\n",
  457.             MAXDUNGEON);
  458.         fprintf(stderr, "To increase the limit edit MAXDUNGEON in global.h\n");
  459.         exit(1);
  460.     }
  461.  
  462.     in_dungeon = 1;
  463.     tmpdungeon[n_dgns].lev.base = 0;
  464.     tmpdungeon[n_dgns].lev.rand = 0;
  465.     tmpdungeon[n_dgns].chance = 100;
  466.     strcpy(tmpdungeon[n_dgns].name, "");
  467.     strcpy(tmpdungeon[n_dgns].protoname, "");
  468.     tmpdungeon[n_dgns].flags = 0;
  469.     tmpdungeon[n_dgns].levels = 0;
  470.     tmpdungeon[n_dgns].branches = 0;
  471.     tmpdungeon[n_dgns].entry_lev = 0;
  472. }
  473.  
  474. void
  475. init_level()
  476. {
  477.     if(++n_levs > LEV_LIMIT) {
  478.  
  479.         yyerror("FATAL - Too many special levels defined.");
  480.         exit(1);
  481.     }
  482.     tmplevel[n_levs].lev.base = 0;
  483.     tmplevel[n_levs].lev.rand = 0;
  484.     tmplevel[n_levs].chance = 100;
  485.     tmplevel[n_levs].rndlevs = 0;
  486.     tmplevel[n_levs].flags = 0;
  487.     strcpy(tmplevel[n_levs].name, "");
  488.     tmplevel[n_levs].chain = -1;
  489. }
  490.  
  491. void
  492. init_branch()
  493. {
  494.     if(++n_brs > BRANCH_LIMIT) {
  495.  
  496.         yyerror("FATAL - Too many special levels defined.");
  497.         exit(1);
  498.     }
  499.     tmpbranch[n_brs].lev.base = 0;
  500.     tmpbranch[n_brs].lev.rand = 0;
  501.     strcpy(tmpbranch[n_brs].name, "");
  502.     tmpbranch[n_brs].chain = -1;
  503. }
  504.  
  505. int
  506. getchain(s)
  507.     char    *s;
  508. {
  509.     int i;
  510.  
  511.     if(strlen(s)) {
  512.  
  513.         for(i = n_levs - tmpdungeon[n_dgns].levels + 1; i <= n_levs; i++)
  514.         if(!strcmp(tmplevel[i].name, s)) return i;
  515.  
  516.         yyerror("Can't locate the specified chain level.");
  517.         return(-2);
  518.     }
  519.     return(-1);
  520. }
  521.  
  522. /*
  523.  *    Consistancy checking routines:
  524.  *
  525.  *    - A dungeon must have a unique name.
  526.  *    - A dungeon must have a originating "branch" command
  527.  *      (except, of course, for the first dungeon).
  528.  *    - A dungeon must have a proper depth (at least (1, 0)).
  529.  */
  530.  
  531. int
  532. check_dungeon()
  533. {
  534.     int i;
  535.  
  536.     for(i = 0; i < n_dgns; i++)
  537.         if(!strcmp(tmpdungeon[i].name, tmpdungeon[n_dgns].name)) {
  538.         yyerror("Duplicate dungeon name.");
  539.         return(0);
  540.         }
  541.  
  542.     if(n_dgns)
  543.       for(i = 0; i < n_brs - tmpdungeon[n_dgns].branches; i++) {
  544.         if(!strcmp(tmpbranch[i].name, tmpdungeon[n_dgns].name)) break;
  545.  
  546.         if(i >= n_brs - tmpdungeon[n_dgns].branches) {
  547.         yyerror("Dungeon cannot be reached.");
  548.         return(0);
  549.         }
  550.       }
  551.  
  552.     if(tmpdungeon[n_dgns].lev.base <= 0 ||
  553.        tmpdungeon[n_dgns].lev.rand < 0) {
  554.         yyerror("Invalid dungeon depth specified.");
  555.         return(0);
  556.     }
  557.     return(1);    /* OK */
  558. }
  559.  
  560. /*
  561.  *    - A level must have a unique level name.
  562.  *    - If chained, the level used as reference for the chain
  563.  *      must be in this dungeon, must be previously defined, and
  564.  *      the level chained from must be "non-probabalistic" (ie.
  565.  *      have a 100% chance of existing).
  566.  */
  567.  
  568. int
  569. check_level()
  570. {
  571.     int i;
  572.  
  573.     if(!in_dungeon) {
  574.         yyerror("Level defined outside of dungeon.");
  575.         return(0);
  576.     }
  577.  
  578.     for(i = 0; i < n_levs; i++)
  579.         if(!strcmp(tmplevel[i].name, tmplevel[n_levs].name)) {
  580.         yyerror("Duplicate level name.");
  581.         return(0);
  582.         }
  583.  
  584.     if(tmplevel[i].chain == -2) {
  585.         yyerror("Invaild level chain reference.");
  586.         return(0);
  587.     } else if(tmplevel[i].chain != -1) {    /* there is a chain */
  588.         if(tmplevel[tmpbranch[i].chain].chance != 100) {
  589.         yyerror("Level cannot chain from a probabalistic level.");
  590.         return(0);
  591.         } else if(tmplevel[i].chain == n_levs) {
  592.         yyerror("A level cannot chain to itself!");
  593.         return(0);
  594.         }
  595.     }
  596.     return(1);    /* OK */
  597. }
  598.  
  599. /*
  600.  *    - A branch may not branch backwards - to avoid branch loops.
  601.  *    - A branch name must be unique.
  602.  *      (ie. You can only have one entry point to each dungeon).
  603.  *    - If chained, the level used as reference for the chain
  604.  *      must be in this dungeon, must be previously defined, and
  605.  *      the level chained from must be "non-probabalistic" (ie.
  606.  *      have a 100% chance of existing).
  607.  */
  608.  
  609. int
  610. check_branch()
  611. {
  612.     int i;
  613.  
  614.     if(!in_dungeon) {
  615.         yyerror("Branch defined outside of dungeon.");
  616.         return(0);
  617.     }
  618.  
  619.     for(i = 0; i < n_dgns; i++)
  620.         if(!strcmp(tmpdungeon[i].name, tmpbranch[n_brs].name)) {
  621.  
  622.         yyerror("Reverse branching not allowed.");
  623.         return(0);
  624.         }
  625.  
  626.     if(tmpbranch[i].chain == -2) {
  627.  
  628.         yyerror("Invaild branch chain reference.");
  629.         return(0);
  630.     } else if(tmpbranch[i].chain != -1) {    /* it is chained */
  631.  
  632.         if(tmplevel[tmpbranch[i].chain].chance != 100) {
  633.         yyerror("Branch cannot chain from a probabalistic level.");
  634.         return(0);
  635.         }
  636.     }
  637.     return(1);    /* OK */
  638. }
  639.  
  640. /*
  641.  *    Output the dungon definition into a file.
  642.  *
  643.  *    The file will have the following format:
  644.  *
  645.  *    [ number of dungeons ]
  646.  *    [ first dungeon struct ]
  647.  *    [ levels for the first dungeon ]
  648.  *      ...
  649.  *    [ branches for the first dungeon ]
  650.  *      ...
  651.  *    [ second dungeon struct ]
  652.  *      ...
  653.  */
  654.  
  655. void
  656. output_dgn()
  657. {
  658.     int    nd, cl = 0, nl = 0,
  659.             cb = 0, nb = 0;
  660.  
  661.     if(++n_dgns <= 0) {
  662.  
  663.         yyerror("FATAL - no dungeons were defined.");
  664.         exit(1);
  665.     }
  666.  
  667.     fwrite((char *)(&n_dgns), sizeof(int), 1, stdout);
  668.     for(nd = 0; nd < n_dgns; nd++) {
  669.  
  670.         fwrite((char *)&tmpdungeon[nd], sizeof(struct tmpdungeon), 1,
  671.                                 stdout);
  672.  
  673.         nl += tmpdungeon[nd].levels;
  674.         for(; cl < nl; cl++)
  675.         fwrite((char *)&tmplevel[cl], sizeof(struct tmplevel), 1,
  676.                                 stdout);
  677.  
  678.         nb += tmpdungeon[nd].branches;
  679.         for(; cb < nb; cb++)
  680.         fwrite((char *)&tmpbranch[cb], sizeof(struct tmpbranch), 1,
  681.                                 stdout);
  682.     }
  683. }
  684.